package com.ndp.fb.walle.business.impl;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageInputStream;

import org.monte.media.jpeg.CMYKJPEGImageReaderSpi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.ndp.fb.constant.CommonConstants;
import com.ndp.fb.enums.ErrorType;
import com.ndp.fb.enums.NotificationMessageKey;
import com.ndp.fb.enums.adresource.AdResourceUploadStatus;
import com.ndp.fb.enums.adresource.ThirdPicReviewStatus;
import com.ndp.fb.exception.BusinessException;
import com.ndp.fb.model.AdResourceComment;
import com.ndp.fb.model.AdResourceStats;
import com.ndp.fb.model.business.bo.nfs.NfsConfig;
import com.ndp.fb.mongo.api.AdResourceStatsMongoService;
import com.ndp.fb.mq.api.producer.EventNotificationMessageProducerService;
import com.ndp.fb.rdb.api.AdPublishConditionRdbService;
import com.ndp.fb.rdb.api.ConnectionObjectRdbService;
import com.ndp.fb.rdb.api.EntrustAccountRdbService;
import com.ndp.fb.rdb.api.UserRdbServices;
import com.ndp.fb.rdb.model.ConnectionObject;
import com.ndp.fb.rdb.model.EntrustAccount;
import com.ndp.fb.rdb.model.User;
import com.ndp.fb.rdb.model.adpublishcondition.RegionAndPriceExt;
import com.ndp.fb.redis.api.RedisDistributedLockService;
import com.ndp.fb.util.DateUtil;
import com.ndp.fb.util.FileUtil;
import com.ndp.fb.util.ImagePHash;
import com.ndp.fb.util.ListUtil;
import com.ndp.fb.util.MathUtil;
import com.ndp.fb.util.StringUtil;
import com.ndp.fb.util.ThreadPool;
import com.ndp.fb.walle.business.AdResourceService;
import com.ndp.fb.walle.model.bo.adresource.result.UploadAdimageBoResult;
import com.ndp.fb.walle.model.vo.adresourcestats.param.AdResourceStatsParam;
import com.ndp.fb.walle.util.FileUploadUtils;
import com.ndp.fb.walle.util.ResponseUtils;
import com.ndpmedia.fb.pmd.nfs.ClientService;

import net.coobird.thumbnailator.Thumbnails;

/**
 * Created by Administrator on 2015/3/26.
 */
@Service
public class AdResourceServiceImpl implements AdResourceService {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Reference
    private ConnectionObjectRdbService connectionObjectRdbService;

    @Autowired
    private NfsConfig nfsConfig;

    @Autowired
    private RedisDistributedLockService redisDistributedLockService;

    @Reference
    private AdResourceStatsMongoService adResourceStatsMongoService;

    @Reference
    private AdPublishConditionRdbService adPublishConditionRdbService;

    @Autowired
    private EventNotificationMessageProducerService eventNotificationMessageProducerService;

    @Reference
    private UserRdbServices userRdbServices;
    @Reference
    private EntrustAccountRdbService entrustAccountRdbService;

    @PostConstruct
    public void init() {
        IIORegistry registry = IIORegistry.getDefaultInstance();
        registry.registerServiceProvider(CMYKJPEGImageReaderSpi.class);
    }


    @Override
    public List<UploadAdimageBoResult> uploadAdImage(List<MultipartFile> fileList, String realPath,
                                                     final String appId, final String appName, final User user) {
        final List<UploadAdimageBoResult> results = new ArrayList<>();
        int fileSize = fileList.size();
        final String imageBathId = com.ndp.fb.util.UUID.get();
        logger.info("本次上传文件个数>>>" + fileSize);

        boolean isThirdPic = false; //外部美宣
        List<Long> roleIds = userRdbServices.getRoleByUser(user.getId());
        if (ListUtil.isNotEmpty(roleIds) && roleIds.contains(CommonConstants.ROLE_OUTERUIDESIGNER)) {
            isThirdPic = true;
        }

        for (int i = 0; i < fileSize; i++) {
            MultipartFile multiFile = fileList.get(i);
            String fileName = multiFile.getOriginalFilename();
            logger.info("fileName >>>" + fileName + "   , OriginalFilename>>>" + multiFile.getOriginalFilename());
            UploadAdimageBoResult uploadResourceBoResult = uploadPerAdImageNew(imageBathId, multiFile, fileName, realPath, user, appName, isThirdPic);
            results.add(uploadResourceBoResult);
        }
        //send ad resource Msg
        //外部美宣上传的 等人工审核通过后再发消息
        //外部美宣 不接受
//        if (isThirdPic) {
//            logger.info("本次上传文件个数>>>角色存在外部美宣角色，不发送消息");
//            return results;
//        }
//        try {
//            ThreadPool.execute(new Runnable() {
//                @Override
//                public void run() {
//                    sendAdRessourceMsg(appId, appName, imageBathId, user, results);
//                }
//            });
//        } catch (Exception e) {
//            logger.error("发送消息异常>>>>", e);
//        }
        return results;
    }

    private void sendAdRessourceMsg(String appId, String appName, String imageBathId, User user, List<UploadAdimageBoResult> results) {
        try {
            int sum = 0;
            for (UploadAdimageBoResult result : results) {
                if (result.getErrorType() == null && !result.isExist()) {
                    sum++;
                }
            }

            StringBuilder sb = new StringBuilder();
            sb.append("有新图片啦！")
                    .append(user.getNickname())
                    .append("给")
                    .append("【").append(appName).append("】")
                    .append("上传了")
                    .append(sum)
                    .append("张新图，点击查看详情吧~");

            List<String> eventValues = new ArrayList<>();
            eventValues.add(user.getNickname());
            eventValues.add(appName);
            eventValues.add(sum+"");

            if (sum > 0) {
                List<User> allUsersByOrgId = userRdbServices.getAllUsersByOrgId(user.getOrgId());
                for (User user1 : allUsersByOrgId) {

                    //外部美宣 不接受
                    List<Long> roleIds = userRdbServices.getRoleByUser(user1.getId());
                    if (ListUtil.isNotEmpty(roleIds) && roleIds.contains(CommonConstants.ROLE_OUTERUIDESIGNER)) {
                        continue;
                    }

                    //没选可以收到
                    if (ListUtil.isNotEmpty(roleIds) && roleIds.contains(CommonConstants.ROLE_UIDESIGNER)) {
                        String msg = sb.toString();
                        logger.info("user1>>" + user1.getTicket() + " , >>" + msg);
                        eventNotificationMessageProducerService.sendMessage(user1.getTicket(), NotificationMessageKey.N_001, eventValues, "/adimages/manager?imageBathId=" + imageBathId);
                    } else {
                        ConnectionObject byUserIdAndAppId = connectionObjectRdbService.findByUserIdAndAppId(user1.getTicket(), appId);
                        if (byUserIdAndAppId == null) {
                            logger.info("user1>>" + user1.getTicket() + " , >> 没有 [" + appName + "] 的权限，不用推送信息");
                        } else {
                            String msg = sb.toString();
                            logger.info("user1>>" + user1.getTicket() + " , >>" + msg);
                            eventNotificationMessageProducerService.sendMessage(user1.getTicket(), NotificationMessageKey.N_001, eventValues, "/adimages/manager?imageBathId=" + imageBathId);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("发送消息异常>>>>", e);
        }
    }


    private UploadAdimageBoResult uploadPerAdImageNew(String imageBathId, MultipartFile multipartFile, String fileName, String contextPath,
                                                      User user, String appName, boolean isThirdPic) {
        UploadAdimageBoResult uploadImageBoResult = new UploadAdimageBoResult();
        File tmpFile = null;
        File litImage = null;
        ErrorType errorType = null;
        String tagMsg = null;
        try {
            logger.info("multipartFile>>>>>" + multipartFile.toString());
            //图片
            tmpFile = FileUploadUtils.multipartFile2File(multipartFile, contextPath);
            BufferedImage image = getImageInputStream(tmpFile);
            int width = image.getWidth();
            int height = image.getHeight();
            ImagePHash imagePHash = new ImagePHash();
            List<String> pHash = imagePHash.getPhashArr(new FileInputStream(tmpFile));
            errorType = imgCanUploadNew(width, height, multipartFile.getSize(), isThirdPic);

            if (errorType == null) {
                String fileMD5String = FileUtil.getFileMd5(tmpFile);
                String lockId = "lock_" + fileMD5String;
                String mongoKey = fileMD5String + "_" + user.getOrgId() + "_" + "1970-01-01";
                if (redisDistributedLockService.tryLock(lockId, 1, TimeUnit.MINUTES)) {
                    try {
                        logger.info("fileMD5String >>>>" + fileMD5String + " orgId>>>>>" + user.getOrgId());
                        AdResourceStats adResourceStats = adResourceStatsMongoService.findByMongodbId(mongoKey);
                        if (adResourceStats == null) {
                            adResourceStats = new AdResourceStats();
                            adResourceStats.setImageBathId(imageBathId);
                            adResourceStats.setMongodbId(mongoKey);
                            adResourceStats.setHeight(height);
                            adResourceStats.setWidth(width);
                            adResourceStats.setDay("1970-01-01");
                            adResourceStats.setIsDelete(0);

                            String imageId = uploadNfsFile(tmpFile);
                            //缩略图
                            litImage = FileUploadUtils.createUUIDNameFile(multipartFile.getOriginalFilename(), contextPath);

                            if (width == height) {
                                Thumbnails.of(tmpFile).forceSize(156, 156).outputQuality(0.5).toFile(litImage);
                                adResourceStats.setResourceType(CommonConstants.RESOURCE_TYPE_CAROUSEL);
                            } else {
                                Thumbnails.of(tmpFile).forceSize(156, 109).outputQuality(0.5).toFile(litImage);
                                adResourceStats.setResourceType(CommonConstants.RESOURCE_TYPE_IMAGE);
                            }

                            String liteImageId = uploadNfsFile(litImage);

                            logger.info("图片在>>>>" + user.getOrgId() + "中没有");

                            adResourceStats.setLitNfsId(liteImageId);
                            adResourceStats.setCreateTime(new Date());
                            adResourceStats.setUserIdSet(Sets.newHashSet(user.getTicket()));
                            adResourceStats.setOrgId(user.getOrgId());
                            adResourceStats.setName(fileName);
                            adResourceStats.setUploadStatus(AdResourceUploadStatus.success.getStatus());
                            adResourceStats.setMd5(fileMD5String);
                            adResourceStats.setImageHash(fileMD5String + "_imagemd5");

                            // 图片访问路径 缩略图访问路径
                            String visitUrl = nfsConfig.getFullAddress() + CommonConstants.SYMBOL_SLASH + imageId;
                            String litImgURL = nfsConfig.getFullAddress() + CommonConstants.SYMBOL_SLASH + liteImageId;

                            adResourceStats.setNfsId(imageId);
                            adResourceStats.setVisitPath(visitUrl);
                            adResourceStats.setLitImgURL(litImgURL);
                            adResourceStats.initStatsData();
                            adResourceStats.setProcessEndTime(System.currentTimeMillis());
                            adResourceStats.setPHash(pHash.toArray(new String[pHash.size()]));
                            /// appName tag
                            ArrayList strings = Lists.newArrayList(appName);
                            Map<String, List<Object>> apps = new HashMap<>();
                            apps.put("application", strings);
                            adResourceStats.setTags(apps);

                            if (isThirdPic) {
                                adResourceStats.setFrom(CommonConstants.IMG_FROM_OUTUI);
                                adResourceStats.setReviewStatus(ThirdPicReviewStatus.WAIT_MACHINE_REVIEW.getCode());
                            } else {
                                adResourceStats.setFrom(CommonConstants.IMG_FROM_INNERUI);
                                adResourceStats.setReviewStatus(ThirdPicReviewStatus.PERSON_REVIEW_PASS.getCode());
                            }

                            String scale = MathUtil.scale(adResourceStats.getWidth(), adResourceStats.getHeight());
                            adResourceStats.setScale(scale);

                            adResourceStatsMongoService.batchSaveByWhereWithoutHistory(Arrays.asList(adResourceStats), new String[]{"mongodbId"});
                        } else {
                            uploadImageBoResult.setIsExist(true);
                            //图片删除
                            if (adResourceStats.getIsDelete() != null && adResourceStats.getIsDelete() == 1) {
                                adResourceStats.setIsDelete(0);
                                Map<String, Object> map = Maps.newHashMap();
                                map.put("deleteUser", "");
                                map.put("deleteTime", "");
                                map.put("isDelete", 0);
                                adResourceStatsMongoService.updateMap(mongoKey, map);

                                Map<String, List> saveTags = Maps.newHashMap();
                                List apps = Lists.newArrayList();
                                apps.add(appName);
                                saveTags.put("application", apps);
                                adResourceStatsMongoService.updateNameAndTags(mongoKey, null, null, null, saveTags, false);
                            } else {
                                //外部设计师，不保存 //增加新上传的app 没有删除，外上传
                                if (!isThirdPic) {   ///外部设计师不让上传
                                    Map<String, List> saveTags = Maps.newHashMap();
                                    Map<String, List<Object>> tmpTags = adResourceStats.getTags();
                                    if (tmpTags != null && tmpTags.get("application") != null) {
                                        List<Object> apps = tmpTags.get("application");
                                        Set appSet = Sets.newHashSet(apps);
                                        appSet.add(appName);
                                        saveTags.put("application", Lists.newArrayList(appSet));
                                    } else {
                                        List apps = Lists.newArrayList();
                                        apps.add(appName);
                                        saveTags.put("application", apps);
                                    }
                                    adResourceStatsMongoService.updateNameAndTags(mongoKey, null, null, null, saveTags, false);
                                }
                            }
                        }

                        uploadImageBoResult.setFileName(adResourceStats.getName());
                        uploadImageBoResult.setMongodbId(adResourceStats.getMongodbId());
                        uploadImageBoResult.setVisitPath(adResourceStats.getVisitPath());
                        uploadImageBoResult.setLitImgURL(adResourceStats.getLitImgURL());
                    } finally {
                        redisDistributedLockService.unLock(lockId);
                    }
                } else {
                    //正在上传
                    errorType = ErrorType.IMAGE_REPEAT_ERROR;
                }
            }

            if (errorType != null) {
                String msg = null;
                uploadImageBoResult.setFileName(multipartFile.getName());
                uploadImageBoResult.setErrorType(errorType);
                if (StringUtils.isNotEmpty(tagMsg)) {
                    msg = ResponseUtils.getMsg(errorType) + " 标签为: " + tagMsg;
                } else {
                    msg = ResponseUtils.getMsg(errorType);
                }
                uploadImageBoResult.setMsg(msg);
                uploadImageBoResult.setCode(errorType.getCode());
            }
        } catch (BusinessException e) {
            logger.error("图片上传异常,", e);
            //图片格式异常
            uploadImageBoResult.setFileName(multipartFile.getName());
            uploadImageBoResult.setErrorType(ErrorType.UPLOAD_RESOURCE_IMG_TYPE_FALI);

        } catch (Exception e) {
            logger.error("图片上传异常,", e);
            throw new RuntimeException(e);
        } finally {
            if (tmpFile != null) {
                tmpFile.delete();
            }
            if (litImage != null) {
                litImage.delete();
            }
        }
        return uploadImageBoResult;
    }


    /**
     * 获取图片的流
     * @param file
     * @return
     * @throws Exception
     */
    public static BufferedImage getImageInputStream(File file) throws Exception {
        BufferedImage img = null;
        ImageInputStream iis = new FileImageInputStream(file);
        try {
            for (Iterator<ImageReader> i = ImageIO.getImageReaders(iis); img == null && i.hasNext(); ) {
                ImageReader r = i.next();
                r.setInput(iis);
                img = r.read(0);
            }
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        } finally {
            iis.close();
        }
        return img;
    }

    private ErrorType imgCanUploadNew(int width, int height, long size, boolean isThirdPic) {
        ErrorType errorType = null;

        //图片大小不能超过7M
        if (size > CommonConstants.FILE_7_M) {
            return ErrorType.IMAGE_SIZE_ERROR;
        }

        if (isThirdPic) { //外部设计师判断
            if (width == height) {
                //轮播长和宽严格相等 并且458_1200
                if (width != CommonConstants.NUM_INT_600) {
                    errorType = ErrorType.IMAGE_PIXEL_C_ERROR;
                }
            } else {
                // 只允许上传分辨率为范围600*314~1200*628的图片
                if (width != CommonConstants.NUM_INT_1200 || height != CommonConstants.NUM_INT_628) {
                    errorType = ErrorType.IMAGE_PIXEL_F_ERROR;
                }
            }
        } else {
            if (width == height) {
                //轮播长和宽严格相等 并且458_1200
                if (width != CommonConstants.NUM_INT_600) {
                    errorType = ErrorType.IMAGE_PIXEL_C_ERROR;
                }
            } else {
                // 只允许上传分辨率为范围600*314~1200*628的图片
                if ((width < CommonConstants.NUM_INT_458 || width > CommonConstants.NUM_INT_1200)
                        || (height < CommonConstants.NUM_INT_458 || height > CommonConstants.NUM_INT_1200)) {
                    errorType = ErrorType.IMAGE_PIXEL_E_ERROR;
                }
            }
        }
        return errorType;
    }

    private String uploadNfsFile(File file) throws Exception {
        ClientService clientService = new ClientService(nfsConfig.getServerIp(), nfsConfig.getServerPort(), nfsConfig.getCharset());
        return clientService.uploadFile(file);
    }



    @Override
    public void saveAdimageTag(String mongodbId, String fileName, List<String> appNames, List<String> countries, List<String> languages,
                               String gender, List<String> interests, User user, Integer reviewStatus) {

        // 处理Tag
        Map<String, List> tags = new HashMap<>();

        if (ListUtil.isNotEmpty(appNames)) {
            tags.put("application", appNames);
        }

        if (ListUtil.isNotEmpty(languages)) {
            tags.put("languages", languages);
        }

        if (org.apache.commons.lang3.StringUtils.isNoneBlank(gender)) {
            tags.put("gender", Arrays.asList(gender));
        }
        adResourceStatsMongoService.updateNameAndTags(mongodbId, fileName, reviewStatus, StringUtil.isEmpty(user.getNickname()) ? user.getUsername() : user.getNickname(), tags, false);
    }

    @Override
    public void saveAdImageComment(String mongodbId, AdResourceComment adResourceComment) {
        adResourceStatsMongoService.updateAdImageComment(mongodbId, adResourceComment);
    }

    @Override
    public List<AdResourceStats> findByMongodbIds(List<String> strings) {
        return adResourceStatsMongoService.findByMongodbIds(strings);
    }

    @Override
    public AdResourceStats findByMongodbId(String mongodbId) {
        return adResourceStatsMongoService.findByMongodbId(mongodbId);
    }

    @Override
    public List<Map<String, Object>> getAppcountries(String ticket, List<String> strings) {

        List<RegionAndPriceExt> regionAndPrices = adPublishConditionRdbService.findAllRegionAndPricesByAppIds(ticket, strings);

        List<Map<String, Object>> appCountriesMap = new ArrayList<>();


        //1. 按照应用分组
        Map<String, List<RegionAndPriceExt>> result = new HashMap<>();
        for (RegionAndPriceExt regionAndPrice : regionAndPrices) {
            String connectionObjectName = regionAndPrice.getConnectionObjectName();
            if (result.containsKey(connectionObjectName)) {
                result.get(connectionObjectName).add(regionAndPrice);
            } else {
                ArrayList<RegionAndPriceExt> objects = Lists.newArrayList();
                objects.add(regionAndPrice);
                result.put(connectionObjectName, objects);
            }
        }

        //2. 获取每个应用的国家
        for (Map.Entry<String, List<RegionAndPriceExt>> longListEntry : result.entrySet()) {
            // appName
            String appName = longListEntry.getKey();
            Set<String> countries = Sets.newHashSet();
            List<RegionAndPriceExt> value = longListEntry.getValue();
            for (RegionAndPriceExt regionAndPrice : value) {
                if ("global".equals(regionAndPrice.getType())) {
                } else if ("country".equals(regionAndPrice.getType())) {
                    String region = regionAndPrice.getRegion();
                    JSONArray objects = JSON.parseArray(region);
                    for (int i = 0; i < objects.size(); i++) {
                        JSONObject jsonObject = (JSONObject) objects.get(i);
                        String name = jsonObject.getString("name");
                        countries.add(name);
                    }
                }
            }

            if (countries.size() > 0) {

                Map<String, Object> tmp = new HashMap<>();
                tmp.put("connectionObjectName", appName);
                tmp.put("countries", countries);
                appCountriesMap.add(tmp);
            }
        }
        return appCountriesMap;
    }

    @Override
    public List<AdResourceStats> getImageStatsGroupByBreakdowns(AdResourceStatsParam adResourceStatsParam) {
        String imageHash = adResourceStatsParam.getImageHash();
        String breakdowns = adResourceStatsParam.getBreakdowns();
        Integer days = adResourceStatsParam.getDays();
        if (org.apache.commons.lang3.StringUtils.isEmpty(imageHash) || org.apache.commons.lang3.StringUtils.isEmpty(breakdowns) || null == days) {
            throw new RuntimeException("参数错误,imageHash,breakdowns和days为必须参数");
        }
        Set<Long> accountSet = Sets.newHashSet();
        if (adResourceStatsParam.getOrgId() != null && adResourceStatsParam.getOrgId() > 0) {
            //必须要根据公司查询
            List<EntrustAccount> adAccountListByOrgId = entrustAccountRdbService.findAdAccountListByOrgId(adResourceStatsParam.getOrgId());
            for (EntrustAccount entrustAccount : adAccountListByOrgId) {
                accountSet.add(entrustAccount.getFbAccountId());
            }
        }
        String since = DateUtil.getDate(new Date(), Calendar.DAY_OF_MONTH, 0 - days, DateUtil.LONG_DATE_FORMAT);
        String util = DateUtil.getDate(new Date(), Calendar.DAY_OF_MONTH, 0, DateUtil.LONG_DATE_FORMAT);
        return adResourceStatsMongoService.getImageStatsGroupByBreakdowns(imageHash, since, util, breakdowns, adResourceStatsParam.isOnlyNew(), accountSet, adResourceStatsParam.getFbConnectionObjectIds());
    }
}
